﻿using Castle.Core.Logging;
using CsvHelper;
using System;
using System.Collections.Generic;
using System.Data;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Yto.Common.CsvConverter;
using Yto.Common.Dependency;

namespace Yto.Common
{
    public static class CsvFileHelper
    {
        private static ILogger logger { get; set; }

        static CsvFileHelper()
        {
            logger = CtnManager.Instance.IsRegisted<ILoggerFactory>() ?
                CtnManager.Instance.Resolver<ILoggerFactory>().Create(typeof(CsvFileHelper))
                : NullLogger.Instance;
        }

        public static Encoding GetEncodeType(string fileName)
        {
            try
            {
                FileStream fs = new FileStream(fileName, FileMode.Open, FileAccess.Read);
                Encoding encodeType = GetEncodeType(fs);
                fs.Close();
                return encodeType;
            }
            catch (Exception ex)
            {
                logger.Error(ex.Message, ex);
            }

            return Encoding.Default;
        }

        public static Encoding GetEncodeType(FileStream stream)
        {
            byte[] Unicode = new byte[] { 0xFF, 0xFE, 0x41 };
            byte[] UnicodeBIG = new byte[] { 0xFE, 0xFF, 0x00 };
            byte[] UTF8 = new byte[] { 0xEF, 0xBB, 0xBF }; //带BOM

            Encoding reVal = Encoding.Default;
            BinaryReader reader = new BinaryReader(stream, Encoding.Default);
            int i;
            int.TryParse(stream.Length.ToString(), out i);

            byte[] bStr = reader.ReadBytes(i);
            if(IsUTF8Bytes(bStr) || (bStr[0] == UTF8[0] && bStr[1] == UTF8[1] && bStr[2] == UTF8[2]))
            {
                reVal = Encoding.UTF8;
            }
            else if (bStr[0] == UnicodeBIG[0] && bStr[1] == UnicodeBIG[1] && bStr[2] == UnicodeBIG[2])
            {
                reVal = Encoding.BigEndianUnicode;
            }
            else if (bStr[0] == Unicode[0] && bStr[1] == Unicode[1] && bStr[2] == Unicode[2])
            {
                reVal = Encoding.Unicode;
            }
            reader.Close();
            return reVal;
        }

        /// <summary>
        /// 判断是否UTF8格式（不带BOM）
        /// </summary>
        /// <param name="data"></param>
        /// <returns></returns>
        private static bool IsUTF8Bytes(byte[] data)
        {
            int charByteCounter = 1;
            byte curByte;
            for(int i = 0; i < data.Length; i++)
            {
                curByte = data[i];
                if(charByteCounter == 1)
                {
                    if(curByte>= 0x80)
                    {
                        while (((curByte <<= 1) & 0x80) != 0)
                        {
                            charByteCounter++;
                        }
                        //标记位首位若为非0，则至少以2个1开始，如：110XXXXX……1111110X
                        if (charByteCounter == 1 || charByteCounter > 6)
                        {
                            return false;
                        }
                    }
                }
                else
                {
                    if((curByte & 0xC0) != 0x80)
                    {
                        return false;
                    }
                    charByteCounter--;
                }
            }
            if (charByteCounter > 1)
            {
                throw new Exception("not known encoding type!");
            }
            return true;
        }

        public static List<T> GetList<T>(string filePath, string format = null,Type mapType = null)
        {
            using (var reader = new StreamReader(filePath, GetEncodeType(filePath)))
            using(var csv = new CsvReader(reader))
            {
                csv.Configuration.TypeConverterCache.AddConverter<DateTime?>(
                    new DateTimeConverter(format));
                if (mapType != null)
                {
                    csv.Configuration.RegisterClassMap(mapType);
                }
                return csv.GetRecords<T>().ToList();
            }
        }

        // 用文本读取方式
        public static DataTable OpenCsv(string filePath)
        {
            Encoding encoding = GetEncodeType(filePath);
            DataTable dt = new DataTable();
            FileStream fs = new FileStream(filePath, FileMode.Open, FileAccess.Read);

            var reader = new StreamReader(fs, encoding);

            string strLine = "";
            string[] arrLine = null;
            string[] tableHead = null;

            int columnCount = 0;
            bool IsFirst = true;

            while ((strLine = reader.ReadLine()) != null)
            {
                if (IsFirst)
                {
                    tableHead = strLine.Split(',');
                    IsFirst = false;
                    columnCount = tableHead.Length;
                    for(int i = 0; i < columnCount; i++)
                    {
                        DataColumn dc = new DataColumn(tableHead[i]);
                        dt.Columns.Add(dc);
                    }
                }
                else
                {
                    arrLine = strLine.Split(',');
                    DataRow dr = dt.NewRow();
                    for(int j = 0; j < columnCount; j++)
                    {
                        dr[j] = arrLine[j];
                    }
                    dt.Rows.Add(dr);
                }
            }

            reader.Close();
            fs.Close();
            return dt;
        }
    }
}
